import { Request, Response, NextFunction } from 'express';
import { db } from '../config/database';
import logger from '../utils/logger';

/**
 * 限流配置选项
 */
export interface RateLimitOptions {
  /** 时间窗口内允许的最大请求数 */
  max: number;
  /** 时间窗口（秒） */
  windowMs: number;
  /** 限流标识符，用于区分不同的限流规则 */
  identifier?: string;
  /** 是否跳过成功请求的计数 */
  skipSuccessfulRequests?: boolean;
  /** 是否跳过失败请求的计数 */
  skipFailedRequests?: boolean;
  /** 自定义key生成器 */
  keyGenerator?: (req: Request) => string;
  /** 自定义错误消息 */
  message?: string;
  /** 当达到限制时的状态码 */
  statusCode?: number;
  /** 响应头配置 */
  standardHeaders?: boolean;
  /** 是否在达到限制时立即返回错误 */
  skipOnError?: boolean;
}

/**
 * 默认key生成器
 */
const defaultKeyGenerator = (req: Request, identifier?: string): string => {
  const userId = req.user?.userId;
  const clientId = userId || req.ip || 'unknown';
  const baseKey = identifier || `${req.method}:${req.route?.path || req.path}`;
  return `ratelimit:${baseKey}:${clientId}`;
};

/**
 * 通用限流中间件
 */
export const rateLimit = (options: RateLimitOptions) => {
  const {
    max,
    windowMs,
    identifier,
    skipSuccessfulRequests = false,
    skipFailedRequests = false,
    keyGenerator,
    message = '请求过于频繁，请稍后再试',
    statusCode = 429,
    standardHeaders = true,
    skipOnError = false,
  } = options;

  return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const redis = await db.redis();
      
      // 生成限流key
      const key = keyGenerator 
        ? keyGenerator(req) 
        : defaultKeyGenerator(req, identifier);
      
      // 获取当前计数
      const current = await redis.incr(key);
      
      // 如果是第一次访问，设置过期时间
      if (current === 1) {
        await redis.expire(key, Math.ceil(windowMs / 1000));
      }
      
      // 设置响应头
      if (standardHeaders) {
        const ttl = await redis.ttl(key);
        const resetTime = Date.now() + (ttl > 0 ? ttl * 1000 : windowMs);
        
        res.set({
          'X-RateLimit-Limit': max.toString(),
          'X-RateLimit-Remaining': Math.max(0, max - current).toString(),
          'X-RateLimit-Reset': resetTime.toString(),
        });
      }
      
      // 检查是否超过限制
      if (current > max) {
        const ttl = await redis.ttl(key);
        
        logger.warn(`限流触发: ${key}, 当前: ${current}, 限制: ${max}`);
        
        res.status(statusCode).json({
          success: false,
          message: message,
          data: {
            limit: max,
            current: current,
            resetTime: ttl > 0 ? ttl : Math.ceil(windowMs / 1000),
          },
        });
        return;
      }
      
      // 如果配置了跳过某些请求的计数，则在响应后处理
      if (skipSuccessfulRequests || skipFailedRequests) {
        const originalSend = res.json;
        res.json = function(data: any) {
          const shouldSkip = 
            (skipSuccessfulRequests && res.statusCode < 400) ||
            (skipFailedRequests && res.statusCode >= 400);
          
          if (shouldSkip) {
            redis.decr(key).catch(err => 
              logger.error('限流计数回退失败:', err)
            );
          }
          
          return originalSend.call(this, data);
        };
      }
      
      next();
    } catch (error: any) {
      logger.error('限流中间件错误:', error);
      
      if (skipOnError) {
        next();
      } else {
        res.status(500).json({
          success: false,
          message: '服务暂时不可用，请稍后再试',
        });
      }
    }
  };
};

/**
 * 预设的限流配置
 */
export const rateLimitPresets = {
  /** 严格限流：每分钟10次 */
  strict: { max: 10, windowMs: 60 * 1000 },
  
  /** 普通限流：每分钟30次 */
  normal: { max: 30, windowMs: 60 * 1000 },
  
  /** 宽松限流：每分钟100次 */
  loose: { max: 100, windowMs: 60 * 1000 },
  
  /** 认证相关：每5分钟5次 */
  auth: { max: 5, windowMs: 5 * 60 * 1000 },
  
  /** 登录限流：每5分钟10次 */
  login: { max: 10, windowMs: 5 * 60 * 1000 },
  
  /** API调用：每小时1000次 */
  api: { max: 1000, windowMs: 60 * 60 * 1000 },
  
  /** 上传限流：每小时20次 */
  upload: { max: 20, windowMs: 60 * 60 * 1000 },
};

/**
 * 快速创建限流中间件的便捷函数
 */
export const createRateLimit = (
  max: number, 
  windowMs: number, 
  identifier?: string
) => {
  return rateLimit({ max, windowMs, identifier });
};

/**
 * 基于IP的限流
 */
export const rateLimitByIP = (options: RateLimitOptions) => {
  return rateLimit({
    ...options,
    keyGenerator: (req: Request) => {
      const baseKey = options.identifier || `${req.method}:${req.route?.path || req.path}`;
      return `ratelimit:ip:${baseKey}:${req.ip}`;
    },
  });
};

/**
 * 基于用户的限流
 */
export const rateLimitByUser = (options: RateLimitOptions) => {
  return rateLimit({
    ...options,
    keyGenerator: (req: Request) => {
      const userId = req.user?.userId || 'anonymous';
      const baseKey = options.identifier || `${req.method}:${req.route?.path || req.path}`;
      return `ratelimit:user:${baseKey}:${userId}`;
    },
  });
};

/**
 * 基于API密钥的限流
 */
export const rateLimitByApiKey = (options: RateLimitOptions) => {
  return rateLimit({
    ...options,
    keyGenerator: (req: Request) => {
      const apiKey = req.headers['x-api-key'] as string || 'no-key';
      const baseKey = options.identifier || `${req.method}:${req.route?.path || req.path}`;
      return `ratelimit:apikey:${baseKey}:${apiKey}`;
    },
  });
};

/**
 * 全局限流中间件
 * 对所有请求进行基础限流
 */
export const globalRateLimit = rateLimit({
  max: 1000,
  windowMs: 15 * 60 * 1000, // 15分钟
  identifier: 'global',
  message: '请求过于频繁，请稍后再试',
  skipOnError: true,
});

export default rateLimit; 